using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using HossMvp.Core;
using HossMvp.WinForms;

namespace Sample.Views
{
    public class PreferencesView : AbstractView, IDisposable
    {
        private readonly EventHandler idleCheck;

        public PreferencesView(AbstractViewManager manager, string name, IContentProvider contents)
            : base(manager, name, contents)
        {
            this.BindCommands();
            this.EnumerateSections();
            ((PreferencesViewContentProvider)contents).View = this;
            this.idleCheck = (s, a) => this.Manager.Presenter.CommandProcessor.Enable();
            Application.Idle += this.idleCheck;
        }

        public void Dispose()
        {
            Application.Idle -= this.idleCheck;
        }

        protected override void BindCommands()
        {
            // Close
            this.Manager.GetCommand("CloseOK").Bind(this.Contents.Get<IComponent>("buttonOK"));
            this.Manager.GetCommand("CloseCancel").Bind(this.Contents.Get<IComponent>("buttonCancel"));
            this.Manager.GetCommand("Apply").Bind(this.Contents.Get<IComponent>("buttonApply"));
            this.Manager.GetCommand("SelectSection")
                .Bind(this.Contents.Get<IComponent>("listBoxSections"), WinFormsEventTypeConstants.SelectedIndexChanged);
        }

        private void EnumerateSections()
        {
            // this is where preferences' section are enumerated so that
            // they are dynamically injected in sections List View

            var sections = new[] { "General", "Editor", "Plugins" };

            var listBox = (ListBox)this.Contents.Get<IComponent>("listBoxSections");
            listBox.Items.Clear();
            foreach (var section in sections)
            {
                listBox.Items.Add(section);
            }
        }

        public void BindModifiedCommand()
        {
            this.Manager.GetCommand("SetPreferencesModified")
                .Bind(this.Contents.Get<ComboBox>("comboBoxLocalization"), WinFormsEventTypeConstants.SelectedIndexChanged)
                .Bind(this.Contents.Get<CheckedListBox>("checkedListBoxToolbars"), WinFormsEventTypeConstants.ItemCheck)
                .Bind(this.Contents.Get<CheckBox>("checkBoxMenuVisible"))
                .Bind(this.Contents.Get<CheckBox>("checkBoxStatusbarVisible"));
        }

        public class PreferencesViewContentProvider : WinFormsContentProvider
        {
            public PreferencesView View { get; set; }   // backlink to PreferencesView

            public PreferencesViewContentProvider(Form form)
                : base(form, new NameDecorator("Preferences"))
            {
                //var decorator = this.Decorator;
                //this.RegisterAction(decorator.NameOf<PreferencesViewContentProvider>(v => v.Show), this.Show);
                //this.RegisterAction(decorator.NameOf<PreferencesViewContentProvider>(v => v.Close), this.Close);
                //this.RegisterAction(decorator.NameOf<PreferencesViewContentProvider>(v => v.SelectSection), this.SelectSection);
                //this.RegisterAction(decorator.NameOf<PreferencesViewContentProvider>(v => v.InitializeSection), this.InitializeSection);
                //this.RegisterAction(decorator.NameOf<PreferencesViewContentProvider>(v => v.GetPreferences), this.GetPreferences);
                //this.RegisterAction(decorator.NameOf<PreferencesViewContentProvider>(v => v.ApplyPreferences), this.ApplyPreferences);
                this.RegisterActions();
            }

            #region Actions

            private ActionResult Show(ActionContext context)
            {
                // initialize with the first (Main) section
                var listBox = this.Get<ListBox>("listBoxSections");
                if (listBox.Items.Count > 0)
                {
                    listBox.SelectedIndex = 0;
                }

                var parent = context.Get<Form>("parent");
                this.Form.ShowDialog(parent);

                return null;
            }

            private ActionResult Close(ActionContext context)
            {
                this.Form.Close();
                return null;
            }

            private ActionResult SelectSection(ActionContext context)
            {
                var listBox = context.Get<ListBox>("sender");
                var result = new ActionResult().WithProperty("selection", listBox.SelectedItem);
                var panelName = "Preferences" + listBox.SelectedItem + "Form";
                var namespacePrefix = this.GetFormNamespace();
                var type = Type.GetType(namespacePrefix + "." + panelName);
                if (type != null)
                {
                    var form = (Form)Activator.CreateInstance(type, this);
                    var panelToInjectField = type.GetField("panelToInject", BindingFlags.NonPublic | BindingFlags.Instance);
                    Debug.Assert(panelToInjectField != null, "panelToInjectField != null");
                    var panelToMove = panelToInjectField.GetValue(form);
                    var splitPanel = this.Get<Panel>("panelHost");
                    splitPanel.Controls.Clear();
                    splitPanel.Controls.Add((Control)panelToMove);
                }

                return result;
            }

            private ActionResult InitializeSection(ActionContext context)
            {
                var section = context.Get<string>("section");
                switch (section)
                {
                    case "General":
                        this.SetGeneralPreferences(context);
                        break;
                }

                return null;
            }

            private ActionResult GetPreferences(ActionContext context)
            {
                var section = context.Get<string>("section");
                var result = new ActionResult();
                switch (section)
                {
                    case "General":
                        result = this.GetGeneralPreferences(context);
                        break;
                }

                return result;
            }

            private ActionResult GetGeneralPreferences(ActionContext context)
            {
                var result = new ActionResult();

                var comboBoxLocalization = this.Get<ComboBox>("comboBoxLocalization");
                result.Set("locallization", comboBoxLocalization.SelectedItem);

                var checkedListBoxToolbars = this.Get<CheckedListBox>("checkedListBoxToolbars");
                var itemIndex = checkedListBoxToolbars.Items.IndexOf("Main");
                var itemChecked = checkedListBoxToolbars.GetItemChecked(itemIndex);
                result.Set("maintoolbar", itemChecked);

                var checkBoxMenuVisible = this.Get<CheckBox>("checkBoxMenuVisible");
                result.Set("mainmenu", checkBoxMenuVisible.Checked);

                var checkBoxStatusbarVisible = this.Get<CheckBox>("checkBoxStatusbarVisible");
                result.Set("statusbar", checkBoxStatusbarVisible.Checked);

                this.View.BindModifiedCommand();

                return result;
            }

            private ActionResult ApplyPreferences(ActionContext context)
            {
                var section = context.Get<string>("section");
                var result = new ActionResult();
                switch (section)
                {
                    case "General":
                        this.ApplyGeneralPreferences(context);
                        break;
                }

                return result;
            }

            #endregion Actions

            #region Helpers (Privates)

            private string GetFormNamespace()
            {
                var preferencesFormType = this.Form.GetType();
                var fullNameParts = preferencesFormType.FullName.Split('.');
                var nsParts = fullNameParts.Take(fullNameParts.Length - 1);
                var result = string.Join(".", nsParts);
                return result;
            }

            private void SetGeneralPreferences(ActionContext context)
            {
                var comboBoxLocalization = this.Get<ComboBox>("comboBoxLocalization");
                var localization = context.Get<string>("locallization");
                comboBoxLocalization.SelectedIndex = comboBoxLocalization.Items.IndexOf(localization);

                var checkedListBoxToolbars = this.Get<CheckedListBox>("checkedListBoxToolbars");
                var itemIndex = checkedListBoxToolbars.Items.IndexOf("Main");
                var itemChecked = context.Get<bool>("maintoolbar");
                checkedListBoxToolbars.SetItemChecked(itemIndex, itemChecked);

                var checkBoxMenuVisible = this.Get<CheckBox>("checkBoxMenuVisible");
                checkBoxMenuVisible.Checked = context.Get<bool>("mainmenu");

                var checkBoxStatusbarVisible = this.Get<CheckBox>("checkBoxStatusbarVisible");
                checkBoxStatusbarVisible.Checked = context.Get<bool>("statusbar");

                this.View.BindModifiedCommand();
            }

            private void ApplyGeneralPreferences(ActionContext context)
            {
                var mainView = this.View.Manager.Views.First(v => v.Name == "MainView");

                var language = context.Get<string>("locallization");
                // do nothing; cannot change now

                var toolStripMain = mainView.Contents.Get<ToolStrip>("toolStripMain");
                toolStripMain.Visible = context.Get<bool>("maintoolbar");

                var menuStripMain = mainView.Contents.Get<MenuStrip>("menuStripMain");
                menuStripMain.Visible = context.Get<bool>("mainmenu");

                var statusStripMain = mainView.Contents.Get<StatusStrip>("statusStripMain");
                statusStripMain.Visible = context.Get<bool>("statusbar");
            }

            #endregion Helpers (Privates)
        }
    }
}